package com.cskaoyan.javase.object._2tostring;

/**
 * Object类当中的toString方法
 * 1.方法的声明
 * public String toString()
 * 没有什么需要注意的，只需要注意这个方法无参，并且有String类型的返回值
 *
 * 2.方法的作用
 *      1. 返回该对象（调用toString方法的对象）的字符串表示。
 *      2. 通常，`toString`方法会返回一个“以文本方式表示”此对象的字符串。
 *      3. 结果应是一个简明但易于读懂的信息表达式。
 *      4. 建议所有子类都重写此方法。
 * 总结，这个方法就是把一个对象变成字符串表示，这个字符串要能够简洁明了的表示这个对象。
 * 最后一句话说明，设计者希望程序员能够根据不同场景，自己去实现toString方法
 *
 * 3.Object类当中的toString方法实现，很简单，就只有一条语句：
 *      return getClass().getName() + "@" + Integer.toHexString(hashCode());
 * 分析:
 *      a.this.getClass()是获取某个类的运行时Class对象
 *      b.this.getClass().getName()获取这个对象的类的全限定类名
 *      c.Integer.toHexString(int)它是将一个int数值（十进制）变成一个十六进制的字符串形式。
 *      d.hashCode()它是通过将对象的地址转换成一个十进制数实现的。
 *          也就是说这个方法的返回值是对象地址值的十进制表示
 * 于是：Object类当中的toString方法默认实现：
 *      全限定类名 + “@” + 十六进制地址值字符串
 *
 * 很显然,当你直接输出一个对象名时,就会输出上述形式.
 * 在Java中如果直接输出一个引用,获取某个引用参与了字符串的拼接运算.
 *      那么:
 *      输出的结果是toString方法的结果
 *      拼接的对象会自动调用toString方法,让字符串参与拼接
 *
 * 在默认情况下,每个对象都使用Object类当中的toString方法默认实现,输出全限定类名和十六进制地址值
 * 在大多数情况下,我们不关心地址值,更希望知道对象的状态(属性的取值)于是需要重写toString方法
 *
 * 4.toString方法的重写
 *      没有固定的格式和规则,根据自己的需要,拼接成员变量的取值即可.
 *      一般情况下,我们直接使用 alt + insert自动生成,不需要手写实现.
 *
 *
 * 5.细节问题:
 *
 *      a.toString方法的作用在大多数情况下就是为了查看成员变量取值的,只需要访问取值即可.
 *          非特殊情况,不要乱写toString方法,比如在toString方法中写赋值,可能会引发错误.
 *      b.在IDEA的debug模式中,当代码运行完创建对象的语句后,会在语句的后面,打印该对象的信息
 *          这是通过调用toString方法实现
 *          当你在toString方法中乱写,就会引发正常run没问题,debug启动就有问题的奇怪现象
 *
 *      总之,不要乱写toString,自动生成就行了.
 *
 *      c.如果类中有引用数据类型的成员变量,那么需要继续重写那个类中的toString方法.
 *
 *      d.在输出引用或者使用引用拼接字符串时,会自动调用该对象的toString方法,需不需要手动写出来呢?
 *      1.可写可不写,根据心情
 *      2.不要写
 *      没有必须,千万不要写出来
 *      写出来后,会可能导致空指针异常
 *      不写出来,隐含的toString方法调用不会产生空指针异常
 *      不要画蛇添足.
 *
 * @since 10:14
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Student s = new Student(18, 100);
        System.out.println(s);
        System.out.println(s + "hello world!");
        System.out.println(s.getAge());*/

        /*Student s = new Student(18, 100, new Cat(1000));
        System.out.println(s);*/

        Student s = new Student(18, 100, null);
        System.out.println(s);
    }
}

class Student {
    private int age;
    private double score;
    private Cat cat;

    public Student() {
    }

    public Student(int age, double score) {
        this.age = age;
        this.score = score;
    }

    public Student(int age, double score, Cat cat) {
        this.age = age;
        this.score = score;
        this.cat = cat;
    }

    @Override
    public String toString() {
        age = 1000;
        return "Student{ age = " + this.age + ", score = " + this.score + ", " + cat + "}";
    }

    public int getAge() {
        return age;
    }

    public double getScore() {
        return score;
    }

}

class Cat {
    double price;

    public Cat() {
    }

    public Cat(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "price=" + price +
                '}';
    }
}